<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="zh-Hans">
<head>
  <!-- hexo-inject:begin --><!-- hexo-inject:end --><meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.3" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/avatar.jpg?v=5.1.3">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/avatar.jpg?v=5.1.3">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/avatar.jpg?v=5.1.3">


  <link rel="mask-icon" href="/images/avatar.jpg?v=5.1.3" color="#222">





  <meta name="keywords" content="Java,并发," />










<meta name="description" content="Java代码在编译后会变成Java字节码，字节码被类加载器加载到JVM里，JVM执行字节码，最终需要转化为汇编指令在CPU上执行，Java中所使用的并发机制依赖于JVM的实现和CPU的指令。 volatile 应用volatile 是轻量级 synchronized，它在多处理器开发中保证了共享变量的“可见性”。  可见性：当一个线程修改一个共享变量时，另外一个线程能读到这个修改后的值。  若 v">
<meta name="keywords" content="Java,并发">
<meta property="og:type" content="article">
<meta property="og:title" content="（二）Java并发机制的底层实现原理">
<meta property="og:url" content="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/index.html">
<meta property="og:site_name" content="Fighter&#39;s Blog">
<meta property="og:description" content="Java代码在编译后会变成Java字节码，字节码被类加载器加载到JVM里，JVM执行字节码，最终需要转化为汇编指令在CPU上执行，Java中所使用的并发机制依赖于JVM的实现和CPU的指令。 volatile 应用volatile 是轻量级 synchronized，它在多处理器开发中保证了共享变量的“可见性”。  可见性：当一个线程修改一个共享变量时，另外一个线程能读到这个修改后的值。  若 v">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/CPU术语.png">
<meta property="og:image" content="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/Java对象头长度.png">
<meta property="og:image" content="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/32位JVM的MarkWord的默认存储结构.png">
<meta property="og:image" content="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/偏向锁的获取和撤销.png">
<meta property="og:image" content="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/轻量级锁及膨胀流程图.png">
<meta property="og:image" content="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/锁的优缺点对比.png">
<meta property="og:image" content="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/原子操作CPU术语.png">
<meta property="og:updated_time" content="2018-03-11T07:50:54.090Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="（二）Java并发机制的底层实现原理">
<meta name="twitter:description" content="Java代码在编译后会变成Java字节码，字节码被类加载器加载到JVM里，JVM执行字节码，最终需要转化为汇编指令在CPU上执行，Java中所使用的并发机制依赖于JVM的实现和CPU的指令。 volatile 应用volatile 是轻量级 synchronized，它在多处理器开发中保证了共享变量的“可见性”。  可见性：当一个线程修改一个共享变量时，另外一个线程能读到这个修改后的值。  若 v">
<meta name="twitter:image" content="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/CPU术语.png">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '5.1.3',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/"/>





  <title>（二）Java并发机制的底层实现原理 | Fighter's Blog</title><!-- hexo-inject:begin --><!-- hexo-inject:end -->
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <!-- hexo-inject:begin --><!-- hexo-inject:end --><div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">Fighter's Blog</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">深度沉迷学习</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="Fighter.">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Fighter's Blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">（二）Java并发机制的底层实现原理</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-03-02T13:16:10+08:00">
                2018-03-02
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Java笔记/" itemprop="url" rel="index">
                    <span itemprop="name">Java笔记</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          
            <span class="post-meta-divider">|</span>
            <span class="page-pv"><i class="fa fa-file-o"></i>
            <span class="busuanzi-value" id="busuanzi_value_page_pv" ></span>
            </span>
          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>Java代码在编译后会变成Java字节码，字节码被类加载器加载到JVM里，JVM执行字节码，最终需要转化为汇编指令在CPU上执行，Java中所使用的并发机制依赖于JVM的实现和CPU的指令。</p>
<h2 id="volatile-应用"><a href="#volatile-应用" class="headerlink" title="volatile 应用"></a>volatile 应用</h2><p><strong>volatile 是轻量级 synchronized</strong>，它在多处理器开发中保证了共享变量的“可见性”。</p>
<blockquote>
<p>可见性：当一个线程修改一个共享变量时，另外一个线程能读到这个修改后的值。</p>
</blockquote>
<p>若 volatile 变量修饰符使用恰当，它<strong>比 synchronized 使用和执行成本更低</strong>，因为它<strong>不会引起线程上下文切换和调度。</strong></p>
<h3 id="volatile-定义与实现原理"><a href="#volatile-定义与实现原理" class="headerlink" title="volatile 定义与实现原理"></a>volatile 定义与实现原理</h3><blockquote>
<p>Java 语言规范对 volatile 的定义：Java 编程语言允许线程访问共享变量，为了确保共享变量能被准确和一致地更新，线程应确保通过排它锁单独获得这个变量。Java 语言提供了 volatile，在某些情况下比锁更加厉害。<strong>若一个字段被声明为 volatile，Java 线程内存模型确保所有线程看到这个变量的值是一致的。</strong><br><a id="more"></a><br>CPU 术语：<br><img src="/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/CPU术语.png" title="CPU术语"></p>
</blockquote>
<p>被 volatile 修饰的共享变量进行写操作时会多第二行汇编代码，其中Lock 前缀的指令在多核处理器下会引发两件事情：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">//Java 代码</div><div class="line">instance = new Singleton(); // instance是volatile变量</div><div class="line">//对应汇编指令</div><div class="line">0x01a3de1d: movb $0×0,0×1104800(%esi);0x01a3de24: lock addl $0×0,(%esp);</div></pre></td></tr></table></figure>
<ol>
<li>Lock前缀指令会引起处理器将当前处理器缓存行的数据写回到系统内存<ul>
<li>Lock前缀指令导致在执行指令期间，声言处理器的LOCK#信号。在多处理器环境中，LOCK#信号确保在声言该信号期间，处理器可以独占任何共享内存（因为它会锁住总线，导致其他CPU不能访问总线，不能访问总线就意味着不能访问系统内存。）。但是，在最近的处理器里，LOCK＃信号一般不锁总线，而是锁缓存，毕竟锁总线开销的比较大。对于Intel486和Pentium处理器，在锁操作时，总是在总线上声言LOCK#信号。但在P6和目前的处理器中，如果访问的内存区域已经缓存在处理器内部，则不会声言LOCK#信号。相反，它会锁定这块内存区域的缓存并回写到内存，并使用缓存一致性机制来确保修改的原子性，此操作被称为“缓存锁定”，缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据。</li>
</ul>
</li>
<li>这个回写内存的操作会使在其它CPU里缓存了该内存地址的数据无效<ul>
<li>IA-32处理器和Intel 64处理器使用MESI（修改、独占、共享、无效）控制协议去维护内部缓存和其他处理器缓存的一致性。在多核处理器系统中进行操作的时候，IA-32和Intel 64处理器能嗅探其他处理器访问系统内存和它们的内部缓存。处理器使用嗅探技术保证它的内部缓存、系统内存和其他处理器的缓存的数据在总线上保持一致。例如，在Pentium和P6 family处理器中，如果通过嗅探一个处理器来检测其他处理器打算写内存地址，而这个地址当前处于共享状态，那么正在嗅探的处理器将使它的缓存行无效，在下次访问相同内存地址时，强制执行缓存行填充。</li>
</ul>
</li>
</ol>
<p>也就是说，为了提高处理速度，处理器不直接和内存进行通信，而是先将系统内存的数据读到内部缓存（L1，L2或其他）后再进行操作，但操作完不知道何时会写到内存。如果对声明了volatile的变量进行写操作，JVM就会向处理器发送一条Lock前缀的指令，将这个变量所在缓存行的数据写回到系统内存。但是，就算写回到内存，如果其他处理器缓存的值还是旧的，再执行计算操作就会有问题。所以，在多处理器下，为了保证各个处理器的缓存是一致的，就会实现缓存一致性协议，每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了，当处理器发现自己缓存行对应的内存地址被修改，就会将当前处理器的缓存行设置成无效状态，当处理器对这个数据进行修改操作的时候，会重新从系统内存中把数据读到处理器缓存里。</p>
<h2 id="synchronized的实现原理与应用"><a href="#synchronized的实现原理与应用" class="headerlink" title="synchronized的实现原理与应用"></a>synchronized的实现原理与应用</h2><p>下面介绍 JavaSE 1.6 为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁，以及锁的存储结构和升级过程。<br>synchronized 实现同步的基础：<strong>Java 中每个对象都可以作为锁。</strong> 具体表现为以下 3 种形式：</p>
<ul>
<li>对于普通同步方法，锁是当前实例对象</li>
<li>对于静态同步方法，锁是当前类的 class 对象</li>
<li>对于同步方法块，锁是 synchronized 括号里配置的对象</li>
</ul>
<p>当一个线程试图访问同步代码块时，它首先必须得到锁，退出或抛出异常时必须释放锁。</p>
<p>JVM 基于进入和退出 monitor 对象来实现方法同步和代码块同步，但两者实现细节不同。代码块同步是使用 <code>monitorenter</code> 和 <code>monitorexit</code> 指令实现，而方法同步是使用另一种方式实现，细节在 JVM 规范没有详细说明。但方法同步同样可以使用这两个指令来实现。</p>
<p>monitorenter 指令是在编译后插入到同步代码块开始位置，而 monitorexit 是插入到方法结束处和异常处，JVM 要保证每个 monitorenter 必须有对应的 monitorexit与之匹配。任何对象都有一个 monitor 与之关联，当且一个 monitor 被持有后，它将处于锁定状态。线程执行到 monitorenter 指令时，将会尝试获取对象所对应的 monitor 的所有权，即尝试获得对象的锁。</p>
<h3 id="Java-对象头"><a href="#Java-对象头" class="headerlink" title="Java 对象头"></a>Java 对象头</h3><p>synchronized用的锁是存在Java对象头里的。如果对象是数组类型，则虚拟机用3个字宽（Word）存储对象头，如果对象是非数组类型，则用2字宽存储对象头。在32位虚拟机中，1字宽等于4字节，即32bit。<br><img src="/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/Java对象头长度.png" title="Java对象头长度"></p>
<p>Java对象头里的Mark Word里默认存储对象的HashCode、分代年龄和锁标记位。<br><img src="/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/32位JVM的MarkWord的默认存储结构.png" title="32位JVM的MarkWord的默认存储结构"></p>
<p>在运行期间，MarkWord 里存储的数据会随着锁标志位的变化而变化：<br></p>
<p>64 位虚拟机下，MarkWord是64bit大小的，其存储结构如下：<br></p>
<h3 id="锁的升级与对比"><a href="#锁的升级与对比" class="headerlink" title="锁的升级与对比"></a>锁的升级与对比</h3><p>Java SE 1.6为了减少获得锁和释放锁带来的性能消耗，引入了“偏向锁”和“轻量级锁”，<strong>在Java SE 1.6中，锁一共有4种状态，级别从低到高依次是：无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态，这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级</strong>，意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略，目的是为了<strong>提高获得锁和释放锁的效率。</strong></p>
<h4 id="偏向锁"><a href="#偏向锁" class="headerlink" title="偏向锁"></a>偏向锁</h4><p>当一个线程访问同步块并获取锁时，会在对象头和栈帧中的锁记录里存储锁偏向的线程ID，以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁，只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果测试成功，表示线程已经获得了锁。如果测试失败，则需要再测试一下Mark Word中偏向锁的标识是否设置成1（表示当前是偏向锁）：如果没有设置，则使用CAS竞争锁；如果设置了，则尝试使用CAS将对象头的偏向锁指向当前线程。</p>
<h5 id="偏向锁的撤销"><a href="#偏向锁的撤销" class="headerlink" title="偏向锁的撤销"></a>偏向锁的撤销</h5><p><strong>偏向锁使用了一种等到竞争出现才释放锁的机制</strong>，所以当其他线程尝试竞争偏向锁时，持有偏向锁的线程才会释放锁。偏向锁的撤销，需要等待<strong>全局安全点</strong>（在这个时间点上没有正在执行的字节码）。它会首先暂停拥有偏向锁的线程，然后检查持有偏向锁的线程是否活着，如果线程不处于活动状态，则将对象头设置成无锁状态；如果线程仍然活着，拥有偏向锁的栈会被执行，遍历偏向对象的锁记录，栈中的锁记录和对象头的Mark Word要么重新偏向于其他线程，要么恢复到无锁或者标记对象不适合作为偏向锁，最后唤醒暂停的线程。<br><img src="/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/偏向锁的获取和撤销.png" title="偏向锁的获取和撤销"></p>
<h5 id="关闭偏向锁"><a href="#关闭偏向锁" class="headerlink" title="关闭偏向锁"></a>关闭偏向锁</h5><ul>
<li><p>偏向锁在Java 6和Java 7里是默认启用，但应用程序启动后几秒才激活，关闭延迟：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">-XX:BiasedLockingStartupDelay=0</div></pre></td></tr></table></figure>
</li>
<li><p>若所有锁通常情况下处于竞争状态，可以通过JVM参数关闭偏向锁，那么程序默认会进入轻量级锁状态：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">-XX:-UseBiasedLocking=false</div></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="轻量级锁"><a href="#轻量级锁" class="headerlink" title="轻量级锁"></a>轻量级锁</h4><h5 id="轻量级锁加锁"><a href="#轻量级锁加锁" class="headerlink" title="轻量级锁加锁"></a>轻量级锁加锁</h5><p>线程在执行同步块之前，JVM会先在当前线程的栈桢中创建用于存储锁记录的空间，并将对象头中的Mark Word复制到锁记录中，官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功，当前线程获得锁，如果失败，表示其他线程竞争锁，当前线程便尝试使用自旋来获取锁。</p>
<h5 id="轻量级锁解锁"><a href="#轻量级锁解锁" class="headerlink" title="轻量级锁解锁"></a>轻量级锁解锁</h5><p>轻量级解锁时，会使用原子的CAS操作将Displaced Mark Word替换回到对象头，如果成功，则表示没有竞争发生。如果失败，表示当前锁存在竞争，锁就会膨胀成重量级锁。图2-2是两个线程同时争夺锁，导致锁膨胀的流程图。</p>
<img src="/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/轻量级锁及膨胀流程图.png" title="轻量级锁及膨胀流程图">
<h4 id="锁的优缺点比较"><a href="#锁的优缺点比较" class="headerlink" title="锁的优缺点比较"></a>锁的优缺点比较</h4><img src="/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/锁的优缺点对比.png" title="锁的优缺点对比">
<h2 id="原子操作的实现原理"><a href="#原子操作的实现原理" class="headerlink" title="原子操作的实现原理"></a>原子操作的实现原理</h2><h3 id="CPU-术语"><a href="#CPU-术语" class="headerlink" title="CPU 术语"></a>CPU 术语</h3><img src="/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/原子操作CPU术语.png" title="原子操作CPU术语">
<h3 id="处理器如何实现原子操作"><a href="#处理器如何实现原子操作" class="headerlink" title="处理器如何实现原子操作"></a>处理器如何实现原子操作</h3><ul>
<li><p>32位IA-32处理器使用<strong>基于对缓存加锁或总线加锁的方式</strong>来实现多处理器之间的原子操作。处理器会自动保证基本的内存操作的原子性。</p>
</li>
<li><p>复杂的内存操作处理器是不能自动保证其原子性的，比如跨总线宽度、跨多个缓存行和跨页表的访问。但是，处理器提供<strong>总线锁定和缓存锁定</strong>两个机制来保证复杂内存操作的原子性。</p>
</li>
</ul>
<h4 id="使用总线锁保证原子性"><a href="#使用总线锁保证原子性" class="headerlink" title="使用总线锁保证原子性"></a>使用总线锁保证原子性</h4><p>如果多个处理器同时对共享变量进行<strong>读改写</strong>操作（i++就是经典的读改写操作），那么共享变量就会被多个处理器同时进行操作，这样读改写操作就不是原子的，操作完之后共享变量的值会和期望的不一致。</p>
<p><strong>处理器使用总线锁就是来解决这个问题的。</strong>所谓总线锁就是使用处理器提供的一个LOCK＃信号，当一个处理器在总线上输出此信号时，其他处理器的请求将被阻塞住，那么该处理器可以独占共享内存。</p>
<h4 id="使用缓存锁保证原子性"><a href="#使用缓存锁保证原子性" class="headerlink" title="使用缓存锁保证原子性"></a>使用缓存锁保证原子性</h4><p><strong>同一时刻只需保证对某个内存地址的操作是原子性即可，</strong>但<strong>总线锁定把CPU和内存之间的通信锁住了</strong>，这使得锁定期间，其他处理器不能操作其他内存地址的数据，所以<strong>总线锁定的开销比较大</strong>，目前处理器在<strong>某些场合下使用缓存锁定代替总线锁定来进行优化。</strong></p>
<p><strong>“缓存锁定”</strong> 是指内存区域如果被缓存在处理器的缓存行中，并且在Lock操作期间被锁定，那么当它执行锁操作回写到内存时，处理器不在总线上声言LOCK＃信号，而是修改内部的内存地址，并允许它的缓存一致性机制来保证操作的原子性，因为缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据，当其他处理器回写已被锁定的缓存行的数据时，会使缓存行无效。</p>
<blockquote>
<p>当操作的数据不能被缓存在处理器内部 / 操作的数据跨多个缓存行（cache line）/ 处理器不支持缓存锁定 这三种情况，处理器会调用总线锁定。</p>
</blockquote>
<h3 id="Java-如何实现原子操作"><a href="#Java-如何实现原子操作" class="headerlink" title="Java 如何实现原子操作"></a>Java 如何实现原子操作</h3><p>在 Java 中可通过<strong>锁和循环CAS</strong>实现原子操作。</p>
<h4 id="使用循环CAS实现原子操作"><a href="#使用循环CAS实现原子操作" class="headerlink" title="使用循环CAS实现原子操作"></a>使用循环CAS实现原子操作</h4><p>JVM中的CAS操作正是利用了处理器提供的CMPXCHG指令实现的。自旋CAS实现的基本思路就是<strong>循环进行CAS操作直到成功为止</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/* 使用CAS实现线程安全计数器 */</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">safeCount</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">for</span> (;;) &#123;</div><div class="line">        <span class="keyword">int</span> i = atomicI.get();</div><div class="line">        <span class="keyword">boolean</span> suc = atomicI.compareAndSet(i, ++i);<span class="comment">//比较值，相等则set</span></div><div class="line">        <span class="keyword">if</span> (suc) &#123;</div><div class="line">            <span class="keyword">break</span>;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"><span class="comment">/* 非线程安全计数器*/</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">count</span><span class="params">()</span> </span>&#123;</div><div class="line">    i++;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h5 id="CAS实现原子操作的三大问题"><a href="#CAS实现原子操作的三大问题" class="headerlink" title="CAS实现原子操作的三大问题"></a>CAS实现原子操作的三大问题</h5><ol>
<li>ABA问题<ul>
<li>一个值原来是A，变成了B，又变成了A，那么使用CAS进行检查时会发现它的值没有发生变化，但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号，每次变量更新的时候把版本号加1，那么A→B→A就会变成1A→2B→3A。</li>
</ul>
</li>
<li>循环时间长开销大</li>
<li>只能保证一个共享变量的原子操作</li>
</ol>
<h4 id="使用锁机制实现原子操作"><a href="#使用锁机制实现原子操作" class="headerlink" title="使用锁机制实现原子操作"></a>使用锁机制实现原子操作</h4><ul>
<li>锁机制保证了只有获得锁的线程才能够操作锁定的内存区域。</li>
<li>JVM内部实现了很多种锁机制，有偏向锁、轻量级锁和互斥锁。</li>
<li>除了偏向锁，JVM实现锁的方式都用了循环CAS，即当一个线程想进入同步块的时候使用循环CAS的方式来获取锁，当它退出同步块的时候使用循环CAS释放锁。</li>
</ul>

      
    </div>
    
    
    

    

    
      <div>
        <div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center;">
  <div>请我喝杯咖啡吧☕~</div>
  <button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
    <span>打赏</span>
  </button>
  <div id="QR" style="display: none;">

    
      <div id="wechat" style="display: inline-block">
        <img id="wechat_qr" src="/images/wechatpay.jpg" alt="Fighter. 微信支付"/>
        <p>微信支付</p>
      </div>
    

    
      <div id="alipay" style="display: inline-block">
        <img id="alipay_qr" src="/images/alipay.jpg" alt="Fighter. 支付宝"/>
        <p>支付宝</p>
      </div>
    

    

  </div>
</div>

      </div>
    

    
      <div>
        <ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者：</strong>
    Fighter.
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/" title="（二）Java并发机制的底层实现原理">http://fighterhit.github.io/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch2-Java并发机制的底层实现原理/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>
    本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/3.0/" rel="external nofollow" target="_blank">CC BY-NC-SA 3.0</a> 许可协议。转载请注明出处！
  </li>
</ul>

      </div>
    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/Java/" rel="tag"># Java</a>
          
            <a href="/tags/并发/" rel="tag"># 并发</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2018/03/02/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch1-并发编程的挑战/" rel="next" title="（一）并发编程的挑战">
                <i class="fa fa-chevron-left"></i> （一）并发编程的挑战
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2018/03/04/Java_Notes/JavaConcurrence/TheArtOfJavaConcurrency/Ch3-Java内存模型/" rel="prev" title="（三）Java内存模型">
                （三）Java内存模型 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
        <!-- JiaThis Button BEGIN -->
<div class="jiathis_style">
<span class="jiathis_txt">分享到：</span>
<a class="jiathis_button_fav">收藏夹</a>
<a class="jiathis_button_tsina">新浪微博</a>
<a class="jiathis_button_qzone">QQ空间</a>
<a class="jiathis_button_weixin">微信</a>
<a class="jiathis_button_cqq">腾讯QQ</a>
<a class="jiathis_button_copy">复制网址</a>
<a class="jiathis_button_share">一键分享</a>

<a href="http://www.jiathis.com/share?uid=2140465" class="jiathis jiathis_txt jiathis_separator jtico jtico_jiathis" target="_blank">更多</a>
<a class="jiathis_counter_style"></a>
</div>
<script type="text/javascript" >
var jiathis_config={
  data_track_clickback:true,
  summary:"",
  shortUrl:false,
  hideMore:false
}
</script>
<script type="text/javascript" src="http://v3.jiathis.com/code/jia.js?uid=" charset="utf-8"></script>
<!-- JiaThis Button END -->
      
    </div>
  </div>


          </div>
          


          
  
    <div class="comments" id="comments">
      <div id="lv-container" data-id="city" data-uid="MTAyMC8zMjY0Ni85MjA3"></div>
    </div>
  


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/images/avatar.jpg"
                alt="Fighter." />
            
              <p class="site-author-name" itemprop="name">Fighter.</p>
              <p class="site-description motion-element" itemprop="description">学习 | 分享 | 交流 | 进步</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">26</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">6</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">28</span>
                  <span class="site-state-item-name">标签</span>
                </a>
              </div>
            

          </nav>

          

          <div class="links-of-author motion-element">
            
              
                <span class="links-of-author-item">
                  <a href="https://github.com/fighterhit" target="_blank" title="GitHub">
                    
                      <i class="fa fa-fw fa-github"></i>GitHub</a>
                </span>
              
                <span class="links-of-author-item">
                  <a href="https://weibo.com/fighterhit" target="_blank" title="Weibo">
                    
                      <i class="fa fa-fw fa-weibo"></i>Weibo</a>
                </span>
              
            
          </div>

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#volatile-应用"><span class="nav-number">1.</span> <span class="nav-text">volatile 应用</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#volatile-定义与实现原理"><span class="nav-number">1.1.</span> <span class="nav-text">volatile 定义与实现原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#synchronized的实现原理与应用"><span class="nav-number">2.</span> <span class="nav-text">synchronized的实现原理与应用</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Java-对象头"><span class="nav-number">2.1.</span> <span class="nav-text">Java 对象头</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#锁的升级与对比"><span class="nav-number">2.2.</span> <span class="nav-text">锁的升级与对比</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#偏向锁"><span class="nav-number">2.2.1.</span> <span class="nav-text">偏向锁</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#偏向锁的撤销"><span class="nav-number">2.2.1.1.</span> <span class="nav-text">偏向锁的撤销</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#关闭偏向锁"><span class="nav-number">2.2.1.2.</span> <span class="nav-text">关闭偏向锁</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#轻量级锁"><span class="nav-number">2.2.2.</span> <span class="nav-text">轻量级锁</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#轻量级锁加锁"><span class="nav-number">2.2.2.1.</span> <span class="nav-text">轻量级锁加锁</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#轻量级锁解锁"><span class="nav-number">2.2.2.2.</span> <span class="nav-text">轻量级锁解锁</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#锁的优缺点比较"><span class="nav-number">2.2.3.</span> <span class="nav-text">锁的优缺点比较</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#原子操作的实现原理"><span class="nav-number">3.</span> <span class="nav-text">原子操作的实现原理</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#CPU-术语"><span class="nav-number">3.1.</span> <span class="nav-text">CPU 术语</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#处理器如何实现原子操作"><span class="nav-number">3.2.</span> <span class="nav-text">处理器如何实现原子操作</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#使用总线锁保证原子性"><span class="nav-number">3.2.1.</span> <span class="nav-text">使用总线锁保证原子性</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#使用缓存锁保证原子性"><span class="nav-number">3.2.2.</span> <span class="nav-text">使用缓存锁保证原子性</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Java-如何实现原子操作"><span class="nav-number">3.3.</span> <span class="nav-text">Java 如何实现原子操作</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#使用循环CAS实现原子操作"><span class="nav-number">3.3.1.</span> <span class="nav-text">使用循环CAS实现原子操作</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#CAS实现原子操作的三大问题"><span class="nav-number">3.3.1.1.</span> <span class="nav-text">CAS实现原子操作的三大问题</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#使用锁机制实现原子操作"><span class="nav-number">3.3.2.</span> <span class="nav-text">使用锁机制实现原子操作</span></a></li></ol></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      
      
    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; 2016 - <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-home"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Fighter.</span>

  
</div>









        
<div class="busuanzi-count">
  <!--<script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>-->
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  
    <span class="site-uv">
      <i class="fa fa-user"></i>
      <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
      
    </span>
  

  
    <span class="site-pv">
      <i class="fa fa-eye"></i>
      <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
      
    </span>
  

    <span class="site-pv">&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
    Hosted by <a target="_blank" href="https://github.com/">GitHub Pages</a>
    </span>

</div>







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.3"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.3"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.3"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.3"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.3"></script>



  


  




	





  





  
    <script type="text/javascript">
      (function(d, s) {
        var j, e = d.getElementsByTagName(s)[0];
        if (typeof LivereTower === 'function') { return; }
        j = d.createElement(s);
        j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
        j.async = true;
        e.parentNode.insertBefore(j, e);
      })(document, 'script');
    </script>
  








  





  

  
<script>
(function(){
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
    }
    else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
})();
</script><!-- hexo-inject:begin --><!-- hexo-inject:end -->


  

  
  


  

  

</body>
</html>
